package com.sunjob.mrogeteway.filter;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.sunjob.common.constant.MROConstant;
import com.sunjob.common.result.Result;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.lang.annotation.Annotation;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Wangzurong
 * @create 2022-08-05 8:09
 * ip 限流过滤器
 */
@Slf4j
public class MROIpPartLimiterFilter implements GatewayFilter, Order {

    private ValueOperations<String, Object> valueOperations;
    private int limit;
    private long limitTime;

    public MROIpPartLimiterFilter(ValueOperations<String, Object> valueOperations, int limit, long limitTime) {
        this.valueOperations = valueOperations;
        this.limitTime = limitTime;
        this.limit = limit;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求ip
        String ipString = exchange.getRequest().getRemoteAddress().getHostString();
        log.info(ipString);
        // 检查请求次数
        if (ipString == null || ipString.trim().length() == 0) {
            // ip地址有误 返回错误信息
            Result<Object> fail = Result.fail("网络错误，请稍后重试");
            String s = JSON.toJSONString(fail);
            DataBuffer wrap = exchange.getResponse().bufferFactory().wrap(s.getBytes());
            exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            return exchange.getResponse().writeWith(Mono.just(wrap));
        }
        String key = MROConstant.USER_RECORDS + ":" + ipString;
        Object o = valueOperations.get(key);
        if (o == null) {
            valueOperations.set(key, 1, limitTime, TimeUnit.MILLISECONDS);
        } else {
            Integer i = (Integer) o;
            // 回写
            try {
               valueOperations.increment(key);
            }catch (Exception e){
                // 已过期
                return chain.filter(exchange);
            }
            if (i + 1 >= limit) {
                // 限流封禁
                Result<Object> fail = Result.fail("你的访问过于频繁，请稍后再试");
                String s = JSON.toJSONString(fail);
                DataBuffer wrap = exchange.getResponse().bufferFactory().wrap(s.getBytes());
                exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return exchange.getResponse().writeWith(Mono.just(wrap));
            }
        }
        // 放行
        return chain.filter(exchange);
    }

    @Override
    public Class<? extends Annotation> annotationType() {
        return null;
    }

    @Override
    public int value() {
        return 1;
    }
}
